package com.guaoran.interview.before.map;

import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author : guCheng
 * @title : HashMapAndConcurrentHashMap
 * @Description : HashMap的底层实现，之后会问ConcurrentHashMap的底层实现；
 * @date :2018年3月10日下午1:01:41
 */
public class HashMapAndConcurrentHashMap {
	/**
	 * <h1>HashMap/HashTable</h1>
	 * <p>0.HashTable:散列值，线程安全的。它的key、value都不可以为null,无序
	 * </p>
	 * <p>1.HashMap :散列值，线程不安全，有可能会造成死循环，无序，单向链表，HashMap的同步处理可以使用Collections类提供的synchronizedMap静态方法<br/>
	 * 		1.1:LinkedHashMap:改下了方法，具有双向链接列表，并允许使用null值和null键，LinkedHashMap的核心就是存在存储顺序和
	 * </p>
	 * <p>2.ConcurrentHashMap:线程安全，采用锁分段技术，利用Segment进行分段，存放HashEntry数组,让锁的粒度更精细一些，并发性能更好。
	 * 	ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成。
	 * 	Segment是一种可重入锁ReentrantLock，在ConcurrentHashMap里扮演锁的角色，HashEntry则用于存储键值对数据。
	 * 	一个ConcurrentHashMap里包含一个Segment数组，Segment的结构和HashMap类似，是一种数组和链表结构， 
	 * 	一个Segment里包含一个HashEntry数组，每个HashEntry是一个链表结构的元素， 每个Segment守护者一个HashEntry数组里的元素,
	 * 	当对HashEntry数组的数据进行修改时，必须首先获得它对应的Segment锁。
	 * </p>
	 */
	/**
	 * ConcurrentHashMap和Hashtable的区别
		Hashtable和ConcurrentHashMap有什么分别呢？
			它们都可以用于多线程的环境，但是当Hashtable的大小增加到一定的时候，性能会急剧下降，因为迭代时需要被锁定很长的时间。
			因为ConcurrentHashMap引入了分割(segmentation)，不论它变得多么大，仅仅需要锁定map的某个部分，而其它的线程不需要等到迭代完成才能访问map。
			简而言之，在迭代的过程中，ConcurrentHashMap仅仅锁定map的某个部分，而Hashtable则会锁定整个map
	 */
	public static void getMapSource() {
		HashMap<String, String> map = new HashMap<>();
		map.put("value", "name");
		map.put("value", "name2");
		map.put("value", "name3");
		ConcurrentHashMap<String, String> cchm = new ConcurrentHashMap<>();
		cchm.put("1", "2");
	}

	public static void main(String[] args) {
//		getMapSource();
		try {
			for (int i = 0; i < 10; i++) {
				hashMapThread();
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public static void hashMapThread() throws InterruptedException {
		final HashMap<String, String> map = new HashMap<String, String>(2);
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 100; i++) {
					System.out.println(i);
					new Thread(new Runnable() {
						@Override
						public void run() {
							map.put(UUID.randomUUID().toString(), "");
						}
					}, "ftf" + i).start();
				}
			}
		}, "ftf");

		t.start();
		t.join();
		System.out.println(map);
	}
}
